package com.codi.api.controller.h5;

import com.codi.base.exception.BaseAppException;
import com.codi.base.exception.ExceptionHandler;
import com.codi.base.log.annotation.Loggable;
import com.codi.base.util.DateUtil;
import com.codi.base.util.EqualsUtil;
import com.codi.base.util.ListUtil;
import com.codi.base.util.StringUtil;
import com.codi.base.web.RequestUtils;
import com.codi.base.web.ResponseUtils;
import com.codi.bus.constant.FundConst;
import com.codi.bus.constant.GlobalConstant;
import com.codi.bus.constant.RuleConstant;
import com.codi.bus.core.domain.FundInfo;
import com.codi.bus.core.domain.Lookup;
import com.codi.bus.core.domain.User;
import com.codi.bus.core.domain.UserBank;
import com.codi.bus.core.jwt.Jwt;
import com.codi.bus.core.resultModel.*;
import com.codi.bus.core.service.*;
import com.codi.bus.core.service.model.BankModel;
import com.codi.bus.core.service.model.T0Model;
import com.codi.bus.core.service.util.FundUtil;
import com.codi.goldlife.external.ExchangeServiceApi;
import com.codi.goldlife.external.databean.ResultBean;
import com.codi.message.constant.ErrorConst;
import com.codi.message.constant.ErrorConstant;
import com.codi.message.util.MessageUtil;
import com.codi.superman.base.domain.SysBanner;
import com.codi.superman.base.service.SysBannerService;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @Author: zengxl
 * @Description: 首页相关控制类
 * @Date:2018/3/8 13:48
 */
@RestController
@Slf4j
public class H5IndexController {

    @Autowired
    private ExchangeServiceApi exchangeServiceApi;
    @Autowired
    private UserService userService;
    @Autowired
    private H5Service h5Service;
    @Autowired
    private T0Service t0Service;
    @Resource(name = "lookupService")
    private LookupService lookupService;
    @Autowired
    private FundCombinationService fundCombinationService;
    @Autowired
    private RedisTemplate<String, String> stringRedisTemplate;
    @Autowired
    private FundInfoService fundInfoService;
    @Autowired
    private FundDetailService fundDetailService;
    @Autowired
    private QueryService queryService;
    @Autowired
    private BankService bankService;
    @Autowired
    private SysBannerService sysBannerService;
    @Autowired
    private PaperInfoService paperInfoService;
    /**
     * 调用用户中心确认第三方账号是否登入状态
     *对风险评测进行了修改
     * 不知道机构是否调用
     * @param channelCode 通道ID
     * @param phone       电话
     * @param token       token验证
     * @param userId      第三方账号ID
     * @return
     */
    @PostMapping("/h5/index")
    @Loggable
    public BaseResult index(@NonNull @RequestParam String channelCode,
                            @RequestParam(required = false) String phone,
                            @RequestParam(required = false) String token,
                            @RequestParam(required = false) String tokenType,
                            @RequestParam(required = false) String userId,
                            @NonNull @RequestParam String redirectType) {
        log.info("接口：/h5/index,第三方账号登入基金H5首页,调用用户中心确认账号信息：通道={},电话={},第三方账号ID={},token={}", channelCode, phone, userId, token);
        BaseResult result = new BaseResult();
        if (StringUtils.isBlank(channelCode)) {
            result.setErrorType(GlobalConstant.ERROR_TYPE_BUSINESS);
            result.setErrorCode(ErrorConstant.ERROR_NOT_LOGIN);
            result.setErrorMessage("登入必要信息存在空值");
            result.setSuccess(false);
            log.warn("接口：/h5/index,登入必要信息存在空值");
            return result;
        }
        Map<String, Object> returnMap = Maps.newHashMap();
        List<SysBanner> listRest = Lists.newArrayList();
        try {
            List<SysBanner> list = sysBannerService.queryBannersUser();
            for(SysBanner banner:list){
                if(banner.getName().endsWith("H5")){
                    listRest.add(banner);
                }
            }
            if(listRest.size()==0){
                listRest.addAll(list);
            }
        } catch (BaseAppException e) {
            e.printStackTrace();
        }
        //未登入状态可以访问首页
        if(StringUtils.isBlank(phone) || StringUtils.isBlank(userId)){
            T0Model model;
            Lookup lookup = lookupService.getLookup(RuleConstant.APP_HOME_DISPLAY_T0);
            if (EqualsUtil.equals(1, lookup.getRuleStatus().intValue())) { // 使用自定义
                model = t0Service.queryT0Fund(false, lookup.getRuleValue());
            } else { // 不是用自定义
                model = t0Service.queryTopRateFund(false);
            }
            returnMap.put("channelCode", channelCode);
            returnMap.put("banners", listRest);
            returnMap.put("T0Recommend", model);
            returnMap.put("protfolioList", fundCombinationService.queryThreeCombinations());
            returnMap.put("redirectType",redirectType);
            returnMap.put("status","-999");
            returnMap.put("totalAsset","");
            result.setSuccess(true);
            result.setResult(returnMap);
            return result;
        }
        User user = userService.getUser(phone);
        if(StringUtils.isNotBlank(tokenType) && EqualsUtil.equals("h5",tokenType) && user != null){
            String tokenValidate = stringRedisTemplate.opsForValue().get(GlobalConstant.H5 + "_" + channelCode + "_token_" + user.getUserId());
            if(StringUtils.isNotEmpty(tokenValidate)){
                if(EqualsUtil.equalsTrim(token,tokenValidate)){
                    log.info("用户token验证成功:uid="+user.getUserId()+" token="+token);
                    stringRedisTemplate.boundValueOps(GlobalConstant.H5 + "_" + channelCode + "_token_" + user.getUserId()).expire(GlobalConstant.H5_TOKEN_ACTIVE_TIME, TimeUnit.MILLISECONDS);
                }else {
                    result.setErrorType(GlobalConstant.ERROR_TYPE_BUSINESS);
                    result.setErrorCode(ErrorConstant.ERROR_NOT_LOGIN);
                    result.setSuccess(false);
                    result.setErrorMessage("用户TOKEN验证错误");
                    log.warn("接口：/h5/index,H5验证TOKEN:用户TOKEN验证错误");
                    return result;
                }
            }else{
                result.setErrorType(GlobalConstant.ERROR_TYPE_BUSINESS);
                result.setErrorCode(ErrorConstant.ERROR_NOT_LOGIN);
                result.setSuccess(false);
                result.setErrorMessage("用户失效");
                log.warn("接口：/h5/index,H5验证TOKEN:用户失效，需要重新登入");
                return result;
            }
        }else {
            ResultBean bean = exchangeServiceApi.validateToken(token, phone, userId);
            if (!bean.isSuccess()) {
                result.setErrorType(GlobalConstant.ERROR_TYPE_BUSINESS);
                result.setErrorCode(ErrorConstant.ERROR_NOT_LOGIN);
                result.setSuccess(false);
                result.setErrorMessage(bean.getErrorMessage());
                log.warn("接口：/h5/index,调用用户中心验证用户返回:{}", bean.getErrorMessage());
                return result;
            }
        }


        int status = -1;


        Boolean isChinaTax = user.getIsChinaTax() != null ? user.getIsChinaTax():false;
        //外部账号未在基金系统里面注册，自动生成基金系统账号信息
        if (user == null || user.getUserId() <= 0) {
            user = new User();
            user.setUserMobile(phone);
            user.setUserName(phone);
            user.setLoginPassword(UUID.randomUUID().toString());//生成随机密码,用户在基金APP上需要走忘记密码流程
            user.setUserState(1);//1:注册、2：绑卡
            user.setCreateDate(new Date());
            user.setIsValid(true);
            user.setIsOrg(false);
            user.setUserFrom(channelCode);
            user = h5Service.addUserByH5(user);
            if (user.getUserId() <= 0) {
                result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
                result.setErrorCode(ErrorConstant.ERROR_NOT_LOGIN);
                result.setSuccess(false);
                result.setErrorMessage("用户未在基金系统注册,自动注册失败!");
                log.error("接口：/h5/index,用户未在基金系统注册,自动注册失败");
                return result;
            }
            status = 1;//未开户
        }else{
            String externalClientId = user.getExternalClientId();
            result.setSuccess(true);
            if (StringUtil.isEmpty(externalClientId)) {
                status = 1;//未开户
            }else{
                List<UserBank> userBanks = bankService.getListByUserId(user.getUserId());
                if (userBanks == null || userBanks.size() == 0) {
                    status = 1;//未开户
                }else{
                    boolean isOpen = false;
                    for (UserBank bankModel : userBanks) {
                        if (!StringUtil.isEmpty(bankModel.getCapitalMode()) && !bankModel.getCapitalMode().equals(GlobalConstant.CAPITAL_MODE_COUNTER)) {
                            isOpen = true;
                            break;
                        }
                    }
                    if (!isOpen) {
                        status = 1;//未开户
                    }else{
                        //判断是否已在私募入口做过风险测评，如果已做过，则传入之前的风险测评结果
                        PaperInfoTestResult privateResult = paperInfoService.getUserPaperInfoTestResult(user.getUserId(), "",null);
                        if (!privateResult.isHave_tested()) {
                            //未做风险评测
                            status = 2;
                        }else{
                            String expireDate = privateResult.getExpire_date();
                            Date now = new Date();
                            Date expire = null;
                            try {
                                expire = DateUtil.parse(expireDate);
                                if (now.after(expire)) {
                                    //风险评测过期
                                    status = 3;
                                }else{
                                    status = 0;//正常
                                }
                            } catch (Exception e) {
                                status = 3;
                            }

                        }
                    }
                }
            }
        }
        String h5Token = "";
        if(StringUtils.isNotBlank(tokenType) && EqualsUtil.equals("h5",tokenType) && token != null){
            h5Token = token;
        }else{
            Date date = new Date();
            Map<String, Object> payload = new HashMap<String, Object>();
            payload.put("uid", String.valueOf(user.getUserId()));// 用户id
            payload.put("iat", date.getTime());// 生成时间:当前
            payload.put("ext", date.getTime() + GlobalConstant.H5_TOKEN_ACTIVE_TIME);// 过期时间
            h5Token = Jwt.createToken(payload);
            stringRedisTemplate.opsForValue().set(GlobalConstant.H5 + "_" + channelCode + "_token_" + user.getUserId(), h5Token, GlobalConstant.H5_TOKEN_ACTIVE_TIME, TimeUnit.MILLISECONDS);
        }
        returnMap.put("channelCode", channelCode);
        returnMap.put("userId", user.getUserId());
        returnMap.put("token", h5Token);
        //TO推荐基金
        boolean isOrg = false;
        if (user.getIsOrg()) {
            isOrg = true;
        }
        T0Model model;
        Lookup lookup = lookupService.getLookup(RuleConstant.APP_HOME_DISPLAY_T0);
        if (EqualsUtil.equals(1, lookup.getRuleStatus().intValue())) { // 使用自定义
            model = t0Service.queryT0Fund(isOrg, lookup.getRuleValue());
        } else { // 不是用自定义
            model = t0Service.queryTopRateFund(isOrg);
        }
        if(status == -1){
            result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
            result.setErrorCode(ErrorConstant.ERROR_NOT_LOGIN);
            result.setSuccess(false);
            result.setErrorMessage("用户开户状态获取失败");
            log.error("接口：/h5/index,用户开户状态获取失败");
            return result;
        }
        String totalAsset = "";
        if(status != 1){
            AssetsResult assets = queryService.queryAssets(user.getUserId());
            if(assets.getTotalWorthValueString() != null){
                totalAsset = assets.getTotalWorthValueString();
            }
        }

        returnMap.put("banners", listRest);
        returnMap.put("T0Recommend", model);
        returnMap.put("protfolioList", fundCombinationService.queryThreeCombinations());
        returnMap.put("totalAsset",totalAsset);
        returnMap.put("redirectType",redirectType);
        returnMap.put("status",status);
        returnMap.put("isChinaTax",isChinaTax);
        result.setSuccess(true);
        result.setResult(returnMap);
        return result;
    }


    /**
     * 瑞富宝列表
     *
     * @return
     * @author mifj
     */
    @GetMapping("/h5/index/ruifubaoList")
    @Loggable
    public BaseResult ruiFuBaoList(HttpServletRequest request) {
        boolean isOrg = false;
        Long userId = Long.valueOf(RequestUtils.getHeader(request, "userid"));
        if (userId != null) {
            User user = userService.getUser(userId);
            if (user.getIsOrg()) {
                isOrg = true;
            }
        }
        Lookup lookup = lookupService.getLookup(RuleConstant.T0FUND_LIST_DISPLAY_FUNDS);
        List<T0Model> data;
        // 使用
        if (EqualsUtil.equals(1, lookup.getRuleStatus().intValue())) {
            String valueStr = lookup.getRuleValue();
            String[] fundCodeArray = valueStr.split(",");
            data = t0Service.queryT0Funds(isOrg, Arrays.asList(fundCodeArray));
            // 不是用
        } else {
            data = t0Service.queryT0Funds(isOrg);
        }
        BaseResult result = new BaseResult();
        return result.setSuccess(true).setResult(data);
    }


    /**
     * 基金排行
     *
     * @param fundTypeCode 基金类型编码
     * @param statisType   统计类型 , 0-8: 日,周,月,季,半年,一年,两年,三年,今年以来(货币类型和短期理财忽略此参数)
     * @param sort         排序；0：升序；1：降序
     * @param pageIndex    页码
     * @param pageSize     记录数
     * @return
     * @throws BaseAppException
     * @author mifj
     */
    @GetMapping("/h5/index/foundList")
    @Loggable
    public FundSortResult foundList(
        @RequestParam(value = "fundTypeCode", defaultValue = "0") Integer fundTypeCode,
        @RequestParam(value = "statisType", defaultValue = "0") Integer statisType,
        @RequestParam(value = "sort", defaultValue = "1") Integer sort,
        @RequestParam(value = "pageIndex", defaultValue = "1") Integer pageIndex,
        @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize) throws BaseAppException {
        switch (fundTypeCode) {
            case 0:
            case FundConst.FUND_TYPE_CODE_STOCK:
            case FundConst.FUND_TYPE_CODE_MIXIN:
            case FundConst.FUND_TYPE_CODE_BOND:
            case FundConst.FUND_TYPE_CODE_INDEX:
            case FundConst.FUND_TYPE_CODE_CURRENCY:
                // case FundConst.FUND_TYPE_CODE_GUARANTEE:保本型合并到混合类型中
            case FundConst.FUND_TYPE_CODE_QDII:
            case FundConst.FUND_TYPE_CODE_SHORT_TERM_FINANCING:
                break;
            default:
                ExceptionHandler.publish(ErrorConst.COMMON_INVALID_FUND_TYPE_CODE);
                break;
        }
        boolean isCurrency = FundUtil.isCurrency(fundTypeCode);
        if ((!isCurrency) && (statisType.intValue() < 0 || statisType.intValue() > 9)) {
            log.error("h5接口:/h5/index/foundList not currency fund, param sort should be in 0-9.");
            ExceptionHandler.publish(ErrorConst.COMMON_INVALID_PARAM_SORT);
        }
        FundSortResult result = new FundSortResult();
        result.setSuccess(true);
        // fundType=0,查询所有在售基金的排序（除了货基）
        // 查询出基金的InnerCodes
        List<String> fundCodes = null;
        List<FundInfo> fundInfos = null;
        if (EqualsUtil.equals(0, fundTypeCode.intValue())) {
            // 注意这里的init size, 排除货基
            List<Integer> fundTypeCodes = new ArrayList<>(7);
            fundTypeCodes.add(FundConst.FUND_TYPE_CODE_STOCK);
            fundTypeCodes.add(FundConst.FUND_TYPE_CODE_MIXIN);
            fundTypeCodes.add(FundConst.FUND_TYPE_CODE_BOND);
            fundTypeCodes.add(FundConst.FUND_TYPE_CODE_GUARANTEE);
            fundTypeCodes.add(FundConst.FUND_TYPE_CODE_INDEX);
            fundTypeCodes.add(FundConst.FUND_TYPE_CODE_OTHER);
            fundTypeCodes.add(FundConst.FUND_TYPE_CODE_QDII);
            fundInfos = fundInfoService.queryFundInfoByTypes(fundTypeCodes);
        } else {
            fundInfos = fundInfoService.queryFundInfoByType(fundTypeCode);
        }
        if (ListUtil.isEmpty(fundInfos)) {
            return result;
        } else {
            fundCodes = new ArrayList<>(fundInfos.size());
            for (FundInfo fund : fundInfos) {
                if (fund.getFundTypeCode() == null) {
                    log.warn("h5接口:/h5/index/foundList fundCode={},fundName={} has no fund type code", fund.getFundCode(), fund.getFundName());
                    continue;
                }
                fundCodes.add(fund.getFundCode());
            }
        }
        result.setSortList(fundDetailService.getSortByNetValuePerformance(fundTypeCode, fundCodes, statisType, sort,
            pageIndex, pageSize));
        return result;
    }

    /**
     * 首页-资产
     *
     * @param request
     * @return
     * @Author mifj
     */
    @GetMapping("/h5/index/assets")
    @Loggable
    public BaseResult assets(HttpServletRequest request) {
        Long userId = Long.valueOf(RequestUtils.getHeader(request, "userid"));
        AssetsResult result = new AssetsResult();
        try {
            result = queryService.queryAssets(userId);
            if (!result.getSuccess() && StringUtil.isEmpty(result.getErrorMessage())) {
                result.setErrorMessage(MessageUtil.getErrorMessage(result.getErrorCode(), null));
            }
        } catch (Exception e) {
            log.error("h5接口:/h5/index/assets 错误信息:{}", e.getMessage());
            e.printStackTrace();
        }
        User user = userService.getUser(userId);
        result.setIsChinaTax(user.getIsChinaTax() != null ? user.getIsChinaTax() : false);
        return result;
    }

    /**
     * 设置 中国税收居民
     *
     * @param request
     * @return
     * @Author mifj
     */
    @GetMapping("/h5/index/setTax")
    @Loggable
    public BaseResult setTax(HttpServletRequest request) {
        Long userId = Long.valueOf(RequestUtils.getHeader(request, "userid"));
        userService.updateChinaTax(userId);
        return null;
    }

    /**
     * 获取我的银行卡信息
     *
     * @param request
     * @param response
     */
    @GetMapping("/h5/index/myBank")
    @Loggable
    public void getBanks(HttpServletRequest request, HttpServletResponse response) {
        BaseListResult result = null;
        // 获取客户编号
        Long userId = Long.valueOf(RequestUtils.getHeader(request, "userid"));
        User userEntity = userService.getUser(userId);
        if (userEntity == null) {
            result = new BankListResult();
            result.setSuccess(false);
            result.setErrorCode(ErrorConstant.ERROR_NO_USER_FIND);
            ResponseUtils.renderJson(request, response, result, true);
            return;
        }
        if (StringUtil.isEmpty(userEntity.getExternalClientId())) {
            result = new BankListResult();
            result.setSuccess(true);
        } else {
            List<UserBank> userBanks = bankService.getListByUserId(userId);
            if (ListUtil.isNotEmpty(userBanks)) {
                result = new BankListResult();
                result.setSuccess(true);
                List<BankModel> banks = new ArrayList<>(userBanks.size());
                userBanks.forEach(bank -> {
                    BankModel bankModel = new BankModel();
                    bankModel.setBranchBank(bank.getBranchbank() == null ? "" : bank.getBranchbank());
                    bankModel.setBranchBankName(bank.getBankBranchName() == null ? "" : bank.getBankBranchName());
                    bankModel.setBankName(bank.getBankName());
                    bankModel.setBankCode(bank.getBankCode());
                    bankModel.setUserBankNo(bank.getUserBankNo());
                    bankModel.setCapitalMode(bank.getCapitalMode());
                    bankModel.setTradeAccount(bank.getExternalTradeAccount());
                    banks.add(bankModel);
                });
                ((BankListResult) result).setBanks(banks);
            }
        }
        ResponseUtils.renderJson(request, response, result, true);
    }
}
